// 用户代码段，这个段中的所有内容将被拷贝到生成的词法类的类声明之前。
import exceptions.*;
import java_cup.runtime.Symbol;

%%
// 参数设置和声明段

// 兼容 cup，等价于以下三条指令
%cup
// %implements java_cup.runtime.Scanner
// %function next_token
// %type java_cup.runtime.Symbol

// 使生成的类是 public 的
%public 
// 告诉 JFlex 生成的类的命名
%class OberonScanner 
// 定义扫描仪将处理的字符集，文本文件使用 unicode 即可
%unicode
// 忽略大小写
%ignorecase
// 打开行计数（当前行号可以通过变量 yyline 访问）
%line 
// 打开列计数（当前列号可以通过变量 yycolumn 访问）
%column
// 列出的异常将在扫描方法的 throws 子句中声明
%yylexthrow LexicalException
// 指定在文件末尾（EOF）时返回的特殊标记的指令
%eofval{
  return new Symbol(OberonSymbol.EOF);
%eofval}

%{
	public int getLine() {
		return yyline + 1;
	}
	public int getColumn() {
		return yycolumn + 1;
	}
%}

// Reserved    = "module"|"procedure"|"begin"|"end"|"const"|"type"|"var"|"record"|"array"|"of"|"while"|"do"|"if"|"then"|"elsif"|"else"|"or"|"div"|"mod" 
// Keyword     = "integer"|"boolean"|"read"|"write"|"writeln"
// Operator    = "("|")"|"["|"]"|"*"|"div"|"mod"|"+"|"-"|"&"|"or"|"~"|":="|"="|"#"|"<"|"<="|">"|">="
// Delimiter   = ";"|","|"."|":"
// Identifier  = [:jletter:]+[:jletterdigit:]*
Identifier  = [a-zA-Z]+[a-zA-Z0-9]*
Integer     = 0[0-7]* | [1-9]+[0-9]*
Comment     = "(*"~"*)"
White       = " "|\t|\b|\f|\r|\n|\r\n

// 非法情况
IllegalOctal        = 0[0-7]* [8|9|"."]+ [0-9]*
IllegalIdentifier   = {Integer}+{Identifier}+
MismatchedComment   = "(*" ( [^\*] | "*"+[^\)] )* | ( [^\(] | "("+[^\*] )* "*)"

%%
// 词法分析段

<YYINITIAL>{ // 全局规则
    // {Reserved}      { return new Symbol(OberonSymbol.RESERVED, yytext()); }
    // {Keyword}       { return new Symbol(OberonSymbol.KEYWORD, yytext()); }
    // {Operator}      { return new Symbol(OberonSymbol.OPERATOR, yytext()); }
    // {Delimiter}     { return new Symbol(OberonSymbol.DELIMITER, yytext()); }
    // 保留字
    "MODULE"    { return new Symbol(OberonSymbol.MODULE, yytext()); }
    "PROCEDURE" { return new Symbol(OberonSymbol.PROCEDURE, yytext()); }
    "BEGIN"     { return new Symbol(OberonSymbol.BEGIN, yytext()); }
    "END"       { return new Symbol(OberonSymbol.END, yytext()); }
    "CONST"     { return new Symbol(OberonSymbol.CONST, yytext()); }
    "TYPE"      { return new Symbol(OberonSymbol.TYPE, yytext()); }
    "VAR"       { return new Symbol(OberonSymbol.VAR, yytext()); }
    "RECORD"    { return new Symbol(OberonSymbol.RECORD, yytext()); }
    "ARRAY"     { return new Symbol(OberonSymbol.ARRAY, yytext()); }
    "OF"        { return new Symbol(OberonSymbol.OF, yytext()); }
    "WHILE"     { return new Symbol(OberonSymbol.WHILE, yytext()); }
    "DO"        { return new Symbol(OberonSymbol.DO, yytext()); }
    "IF"        { return new Symbol(OberonSymbol.IF, yytext()); }
    "THEN"      { return new Symbol(OberonSymbol.THEN, yytext()); }
    "ELSIF"     { return new Symbol(OberonSymbol.ELSIF, yytext()); }
    "ELSE"      { return new Symbol(OberonSymbol.ELSE, yytext()); }
    // 关键字
    // "INTEGER"   { return new Symbol(OberonSymbol.INTEGER, yytext()); }
    // "BOOLEAN"   { return new Symbol(OberonSymbol.BOOLEAN, yytext()); }
    // "READ"      { return new Symbol(OberonSymbol.READ, yytext()); }
    // "WRITE"     { return new Symbol(OberonSymbol.WRITE, yytext()); }
    // "WRITELN"   { return new Symbol(OberonSymbol.WRITELN, yytext()); }
    // 括号 [ ] ( ) 
    "["         { return new Symbol(OberonSymbol.L_SQRUARE_BRACKET, yytext()); }
    "]"         { return new Symbol(OberonSymbol.R_SQRUARE_BRACKET, yytext()); }
    "("         { return new Symbol(OberonSymbol.L_ROUND_BRACKET, yytext()); }
    ")"         { return new Symbol(OberonSymbol.R_ROUND_BRACKET, yytext()); }
    // 算术
    "+"         { return new Symbol(OberonSymbol.PLUS, yytext()); }
    "-"         { return new Symbol(OberonSymbol.MINUS, yytext()); }
    "*"         { return new Symbol(OberonSymbol.TIMES, yytext()); }
    "DIV"       { return new Symbol(OberonSymbol.DIVIDE, yytext()); }
    "MOD"       { return new Symbol(OberonSymbol.MOD, yytext()); }
    // 逻辑
    "OR"        { return new Symbol(OberonSymbol.OR, yytext()); }
    "&"         { return new Symbol(OberonSymbol.AND, yytext()); }
    "~"         { return new Symbol(OberonSymbol.NOT, yytext()); }
    
    // 比较
    "="         { return new Symbol(OberonSymbol.EQ, yytext()); }
    "#"         { return new Symbol(OberonSymbol.NEQ, yytext()); }
    "<"         { return new Symbol(OberonSymbol.LT, yytext()); }
    "<="        { return new Symbol(OberonSymbol.LE, yytext()); }
    ">"         { return new Symbol(OberonSymbol.GT, yytext()); }
    ">="        { return new Symbol(OberonSymbol.GE, yytext()); }
    // 赋值
    ":="        { return new Symbol(OberonSymbol.ASSIGN, yytext()); }
    // 分隔符
    ";"         { return new Symbol(OberonSymbol.SEMICOLON, yytext()); }
    ","         { return new Symbol(OberonSymbol.COMMA, yytext()); }
    "."         { return new Symbol(OberonSymbol.PERIOD, yytext()); }
    ":"         { return new Symbol(OberonSymbol.COLON, yytext()); }
    {Identifier}    {
                        if (yylength() > 24)
                            throw new LexicalException("词法错误：" + yytext());
                        else
                            return new Symbol(OberonSymbol.IDENTIFIER, yytext());
                    }
    {Integer}       {
                        if (yylength() > 12)
                            throw new LexicalException("词法错误：" + yytext());
                        else
                            return new Symbol(OberonSymbol.INTEGER_NUMBER, yytext());
                    }
    {Comment}       {}
    {White}         {}

    // 非法部分
    .                   { throw new LexicalException("词法错误：" + yytext()); }
    {IllegalOctal}      { throw new LexicalException("词法错误：" + yytext()); }
    {IllegalIdentifier} { throw new LexicalException("词法错误：" + yytext()); }
    {MismatchedComment} { throw new LexicalException("词法错误：" + yytext()); }

}